home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
dvitops
/
dvi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-25
|
15KB
|
626 lines
static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/dvi.c,v 1.6 90/08/14 13:09:18 jjc Rel $";
#include "dvitops.h"
static struct stack {
integer h, v, w, x, y, z;
} *stack;
struct addr_count0 {
integer addr;
integer count0;
};
struct postamble_info {
integer num;
integer den;
int mag;
integer last_bop; /* address of last bop */
int npages;
int stack_size;
};
#ifdef PROTO
static void first_pass(int, long *, int, struct addr_count0 *);
static void read_page(struct page_info *page);
static int read_opcode(void);
static void read_postamble(struct postamble_info *postamble);
static void bad_dvi_file(void);
static int count_compare(char *p1, char *p2);
#else
static void first_pass();
static void read_page();
static int read_opcode();
static void read_postamble();
static void bad_dvi_file();
static int count_compare();
#endif
#if 0
typedef enum { SET_CHAR_0 = 0, SET1 = 128, SET_RULE = 132, PUT1 = 133,
PUT_RULE = 137, BOP = 139, EOP = 140, PUSH = 141, POP = 142, RIGHT1 = 143,
W0 = 147, W1 = 148, X0 = 152, X1 = 153, DOWN1 = 157, Y0 = 161, Y1 = 162,
Z0 = 166, Z1 = 167, FNT_NUM_0 = 171, FNT1 = 235, NOP = 138, XXX1 = 239,
FNT_DEF1 = 243, PRE = 247, POST = 248, POST_POST = 249 } dvi_opcode;
#else
#define SET_CHAR_0 0
#define SET1 128
#define SET_RULE 132
#define PUT1 133
#define PUT_RULE 137
#define BOP 139
#define EOP 140
#define PUSH 141
#define POP 142
#define RIGHT1 143
#define W0 147
#define W1 148
#define X0 152
#define X1 153
#define DOWN1 157
#define Y0 161
#define Y1 162
#define Z0 166
#define Z1 167
#define FNT_NUM_0 171
#define FNT1 235
#define NOP 138
#define XXX1 239
#define FNT_DEF1 243
#define PRE 247
#define POST 248
#define POST_POST 249
#endif
static FILE *dvifp;
#define SPECIAL_BUF_SIZE 2048
static char special_buf[SPECIAL_BUF_SIZE];
static void first_pass(totalpages, start_page, maxpages, pagevec)
int totalpages, maxpages;
long start_page[10];
struct addr_count0 *pagevec;
{
integer count[10];
int pageno;
int started = FALSE;
int selected = FALSE;
int pages_selected = 0;
fseek(dvifp, 14L, 0);
if (fseek(dvifp, (long)uread1(dvifp), 1) != 0)
bad_dvi_file();
for (pageno = 0; pageno < totalpages; pageno++) {
unsigned char opcode;
int i;
int donepage = FALSE;
int f = -1;
pagevec[pageno].addr = ftell(dvifp);
while (!donepage) {
unsigned char c;
integer n = 0;
/* deal with the most common case in its own loop */
while ((opcode = uread1(dvifp)) <= 127) {
if (feof(dvifp) || ferror(dvifp))
bad_dvi_file();
if (selected)
used_char(f, opcode);
}
/* we use the fact that SET_CHAR_0 is 0 */
if (FNT_NUM_0 <= opcode && opcode <= FNT_NUM_0 + 63) {
n = opcode - FNT_NUM_0;
opcode = FNT1;
}
else
switch (opcode) {
case SET1 + 3 : case PUT1 + 3 : case XXX1 + 3:
case FNT_DEF1 + 3: case FNT1 + 3:
n = sread4(dvifp); break;
case SET1 + 2 : case PUT1 + 2 : case XXX1 + 2:
case FNT_DEF1 + 2: case FNT1 + 2:
n = uread3(dvifp); break;
case SET1 + 1 : case PUT1 + 1 : case XXX1 + 1:
case FNT_DEF1 + 1: case FNT1 + 1:
n = uread2(dvifp); break;
case SET1 : case PUT1 : case XXX1:
case FNT_DEF1: case FNT1:
n = uread1(dvifp); break;
case RIGHT1 + 3: case W1 + 3: case X1 + 3:
case DOWN1 + 3: case Y1 + 3: case Z1 + 3:
(void)uread1(dvifp);
/* falls through */
case RIGHT1 + 2: case W1 + 2: case X1 + 2:
case DOWN1 + 2: case Y1 + 2: case Z1 + 2:
(void)uread1(dvifp);
/* falls through */
case RIGHT1 + 1: case W1 + 1: case X1 + 1:
case DOWN1 + 1: case Y1 + 1: case Z1 + 1:
(void)uread1(dvifp);
/* falls through */
case RIGHT1: case W1: case X1:
case DOWN1: case Y1: case Z1:
(void)uread1(dvifp);
break;
case SET_RULE: case PUT_RULE :
sread4(dvifp); sread4(dvifp);
break;
}
switch (opcode) {
case SET1 + 3 : case SET1 + 2 : case SET1 + 1 : case SET1 :
case PUT1 + 3 : case PUT1 + 2 : case PUT1 + 1 : case PUT1 :
if (!selected)
break;
c = (unsigned char) n;
if (n >= MAXCHARS || n < 0)
message(ERROR,
"character code %ld too large: using %d instead",
(long)n, c);
used_char(f, c);
break;
case BOP :
for (i = 0; i < 10; ++i)
count[i] = sread4(dvifp);
pagevec[pageno].count0 = count[0];
(void) sread4(dvifp);
if (!started) {
int j;
started = TRUE;
for (j = 0; j < 10; j++)
if (start_page[j] != WILD
&& start_page[j] != count[j])
started = FALSE;
}
if (started && ++pages_selected <= maxpages)
selected = TRUE;
else {
selected = FALSE;
pagevec[pageno].addr = -1;
}
break;
case EOP :
if (selected)
store_page_usage();
donepage = TRUE;
break;
case FNT1 : case FNT1 + 1 : case FNT1 + 2 : case FNT1 + 3 :
if (!selected)
break;
if (n < 0 || n >= MAXFONTS)
/* this should have been spotted in the postamble */
cant_happen();
f = (int) n;
break;
case XXX1 + 3 : case XXX1 + 2 : case XXX1 + 1 : case XXX1:
if (n >= SPECIAL_BUF_SIZE) {
message(ERROR,
"special string too long: ignoring it");
fseek(dvifp, (long)n, 1);
break;
}
fread(special_buf, 1, (size_t)n, dvifp);
special_buf[n] = '\0';
STRXCHAR(special_buf)
if (selected)
special(PASS1, special_buf,(integer)0,(integer)0);
break;
case FNT_DEF1 : case FNT_DEF1 + 1 :
case FNT_DEF1 + 2 : case FNT_DEF1 + 3 :
fseek(dvifp, 12L, 1);
n = uread1(dvifp);
n += uread1(dvifp);
fseek(dvifp, (long)n, 1);
break;
case POST :
bad_dvi_file();
default :
break;
}
}
}
}
static int read_opcode()
{
for (;;) {
int c = uread1(dvifp);
if (c == EOF)
cant_happen();
if (XXX1 <= c && c <= XXX1 + 3) {
integer k;
switch (c) {
case XXX1 :
k = uread1(dvifp); break;
case XXX1 + 1:
k = uread2(dvifp); break;
case XXX1 + 2:
k = uread3(dvifp); break;
case XXX1 + 3:
k = sread4(dvifp); break;
}
fseek(dvifp, (long)k, 1);
}
else if (c != NOP)
return c;
}
}
static void read_postamble(postamble)
struct postamble_info *postamble;
{
int c;
integer n;
long offset;
/* Avoid using a negative offset.
Some implementations can't handle this. */
if (fseek(dvifp, 0L, 2) != 0)
message(FATAL_ERROR, "can't perform seek on dvi file");
offset = ftell(dvifp);
do {
offset--;
fseek(dvifp, offset, 0);
c = uread1(dvifp);
} while (c == 223);
if (c != ID_BYTE)
message(FATAL_ERROR, "this is the wrong type of dvi file");
offset -= 5;
fseek(dvifp, offset, 0);
if (uread1(dvifp) != POST_POST)
cant_happen();
offset = sread4(dvifp);
fseek(dvifp, offset, 0);
if (uread1(dvifp) != POST)
cant_happen();
postamble->last_bop = sread4(dvifp);
postamble->num = sread4(dvifp);
postamble->den = sread4(dvifp);
n = sread4(dvifp);
if (postamble->mag == 0) {
postamble->mag = (int)n;
if (n < 0 || n > INT_MAX) {
message(ERROR, "bad magnification: using 1000 instead");
n = 1000;
}
}
(void) sread4(dvifp);
(void) sread4(dvifp);
postamble->stack_size = sread2(dvifp);
postamble->npages = sread2(dvifp);
while ((c = read_opcode()) >= FNT_DEF1 && c <= FNT_DEF1 + 3) {
integer k;
integer cs, s, d;
int a, l;
char area[257];
char name[257];
switch (c + 1 - FNT_DEF1) {
case 1:
k = uread1(dvifp); break;
case 2:
k = uread2(dvifp); break;
case 3:
k = uread3(dvifp); break;
case 4:
k = sread4(dvifp); break;
}
cs = sread4(dvifp);
s = sread4(dvifp);
d = sread4(dvifp);
a = uread1(dvifp);
l = uread1(dvifp);
if (a)
fread(area, 1, a, dvifp);
area[a] = '\0';
fread(name, 1, l, dvifp);
name[l] = '\0';
STRXCHAR(name)
STRXCHAR(area)
f_def(k, name, area, cs, s, d, postamble->mag);
}
if (c != POST_POST)
cant_happen();
}
static int count_compare(p1, p2)
char *p1, *p2;
{
integer n1 = ((struct addr_count0 *)p1)->count0;
integer n2 = ((struct addr_count0 *)p2)->count0;
if (n1 == n2)
return (int)(((struct addr_count0 *)p1)->addr -
((struct addr_count0 *)p2)->addr);
else if (n1 <= 0 || n2 <= 0) {
if (n2 > 0)
return -1;
else if (n1 > 0)
return 1;
else
return (int)(n2 - n1);
}
else
return (int)(n1 - n2);
}
void read_dvi_file(fp, ofp, option)
FILE *fp, *ofp;
struct option_info *option;
{
struct postamble_info postamble;
struct page_info page;
FILE *psfp;
int i;
int actual_npages;
struct addr_count0 *pagevec;
dvifp = fp;
postamble.mag = option->mag;
read_postamble(&postamble);
if ((stack =
(struct stack *)malloc(sizeof(struct stack)*postamble.stack_size))
== NULL)
out_of_memory();
if ((pagevec = (struct addr_count0 *)malloc((1 + postamble.npages)
*sizeof(struct addr_count0))) == NULL)
out_of_memory();
first_pass(postamble.npages, option->start_page, option->maxpages,
pagevec);
psfp = ofp;
#ifdef HAVE_SETVBUF
setvbuf(psfp, (char *)NULL, _IOFBF, 16384); /* ignore any error */
#endif
for (i = 0, actual_npages = 0; i < postamble.npages; i++)
if (pagevec[i].addr != -1L)
actual_npages++;
prologue(psfp, actual_npages, option->reverse, option->paper);
page.num = postamble.num;
page.den = postamble.den;
page.hoffset = option->hoffset;
page.voffset = option->voffset;
page.copies = option->copies;
page.paper = option->paper;
page.max_drift = (int)((254000.0/page.num) * (page.den/(double)dpi) * 2.0);
if (option->sort)
qsort((char *)pagevec, postamble.npages, sizeof(struct addr_count0),
count_compare);
if (option->reverse) {
for (i = postamble.npages - 1; i >= 0; i--)
if (pagevec[i].addr != -1L) {
page.address = pagevec[i].addr;
page.mag = postamble.mag;
read_page(&page);
}
}
else {
for (i = 0; i < postamble.npages; i++)
if (pagevec[i].addr != -1L) {
page.address = pagevec[i].addr;
page.mag = postamble.mag;
read_page(&page);
}
}
trailer();
}
static void read_page(page)
struct page_info *page;
{
unsigned char opcode;
int had_large_hmotion = FALSE;
int i;
char buf[512];
int nbuf = 0; /* number of characters in buf */
integer endh = 0, rounded_endh = 0;
integer h, v, w, x, y, z;
struct stack *sp = stack;
int f = -1;
integer fs = 0; /* = f_space(f) */
h = v = w = x = y = z = 0;
fseek(dvifp, (long)page->address, 0);
for (;;) {
integer starth;
integer startv;
int startf;
unsigned char c;
integer a, b;
integer wd;
integer n = (integer)0;
opcode = uread1(dvifp);
/* we use the fact that SET_CHAR_0 is 0 */
if (opcode <= 127) {
/* we checked for eof and error on pass 1 */
n = opcode;
opcode = SET1;
}
else if (FNT_NUM_0 <= opcode && opcode <= FNT_NUM_0 + 63) {
n = opcode - FNT_NUM_0;
opcode = FNT1;
}
else
switch (opcode) {
case SET1 + 3 : case PUT1 + 3 : case XXX1 + 3:
case RIGHT1 + 3: case W1 + 3: case X1 + 3:
case DOWN1 + 3: case Y1 + 3: case Z1 + 3:
case FNT_DEF1 + 3: case FNT1 + 3:
n = sread4(dvifp); break;
case SET1 + 2 : case PUT1 + 2 : case XXX1 + 2:
case FNT_DEF1 + 2: case FNT1 + 2:
n = uread3(dvifp); break;
case SET1 + 1 : case PUT1 + 1 : case XXX1 + 1:
case FNT_DEF1 + 1: case FNT1 + 1:
n = uread2(dvifp); break;
case SET1 : case PUT1 : case XXX1:
case FNT_DEF1: case FNT1:
n = uread1(dvifp); break;
case RIGHT1 + 2: case W1 + 2: case X1 + 2:
case DOWN1 + 2: case Y1 + 2: case Z1 + 2:
n = sread3(dvifp); break;
case RIGHT1 + 1: case W1 + 1: case X1 + 1:
case DOWN1 + 1: case Y1 + 1: case Z1 + 1:
n = sread2(dvifp); break;
case RIGHT1: case W1: case X1:
case DOWN1: case Y1: case Z1:
n = sread1(dvifp); break;
}
switch (opcode) {
case SET1 + 3 : case SET1 + 2 : case SET1 + 1 : case SET1 :
case PUT1 + 3 : case PUT1 + 2 : case PUT1 + 1 : case PUT1 :
/* we checked it wasn't out of range on pass 1 */
c = (unsigned char)n;
if (nbuf > 0 &&
(h != endh || v != startv || f != startf
|| had_large_hmotion
|| nbuf >= sizeof(buf)
|| endh - rounded_endh > page->max_drift
|| endh - rounded_endh < -page->max_drift)) {
set_string(buf, nbuf, startf, starth, startv);
nbuf = 0;
}
if (nbuf == 0) {
if (endh != rounded_endh && !had_large_hmotion) {
if (rounded_endh - endh > page->max_drift)
starth = h + page->max_drift;
else if (rounded_endh - endh < -page->max_drift)
starth = h - page->max_drift;
else
starth = h + (rounded_endh - endh);
}
else
starth = h;
endh = h;
rounded_endh = starth;
startv = v;
startf = f;
had_large_hmotion = FALSE;
}
buf[nbuf++] = c;
used_char(f, c);
wd = f_width(f, c);
endh += wd;
rounded_endh += f_rounded_width(f, c);
/* we rely on the fact that SET1 < PUT1 */
if (opcode < PUT1)
h += wd;
break;
case SET_RULE : case PUT_RULE :
a = sread4(dvifp);
b = sread4(dvifp);
set_rule(a, b, h, v);
if (opcode == SET_RULE)
h += b;
break;
case NOP :
break;
case BOP :
for (i = 0; i < 10; ++i)
page->count[i] = sread4(dvifp);
(void) sread4(dvifp);
break;
case EOP :
if (nbuf)
set_string(buf, nbuf, startf, starth, startv);
eop(page);
return;
case PUSH :
sp->h = h; sp->v = v; sp->w = w;
sp->x = x; sp->y = y; sp->z = z;
++sp;
break;
case POP :
--sp;
h = sp->h; v = sp->v; w = sp->w;
x = sp->x; y = sp->y; z = sp->z;
break;
case RIGHT1 : case RIGHT1 + 1 :
case RIGHT1 + 2 : case RIGHT1 + 3 :
h += n;
if (n >= fs || n <= fs*-4)
had_large_hmotion = TRUE;
break;
case W0 :
h += w;
break;
case W1 : case W1 + 1 : case W1 + 2 : case W1 + 3 :
h += w = n;
break;
case X0 :
h += x;
break;
case X1 : case X1 + 1 : case X1 + 2 : case X1 + 3 :
h += x = n;
break;
case DOWN1 : case DOWN1 + 1 : case DOWN1 + 2 : case DOWN1 + 3:
v += n;
break;
case Y0 :
v += y;
break;
case Y1 : case Y1 + 1 : case Y1 + 2 : case Y1 + 3 :
v += y = n;
break;
case Z0 :
v += z;
break;
case Z1 : case Z1 + 1 : case Z1 + 2 : case Z1 + 3 :
v += z = n;
break;
case FNT1 : case FNT1 + 1 : case FNT1 + 2 : case FNT1 + 3 :
if (n < 0 || n >= MAXFONTS)
/* this should have caused a fatal error on pass 1 */
cant_happen();
f = (int)n;
fs = f_space(f);
break;
case XXX1 + 3 : case XXX1 + 2 : case XXX1 + 1 : case XXX1 :
if (n >= SPECIAL_BUF_SIZE) {
/* we printed an error on the first pass */
fseek(dvifp, (long)n, 1);
break;
}
if (nbuf > 0) { /* flush buf */
set_string(buf, nbuf, startf, starth, startv);
nbuf = 0;
}
fread(special_buf, 1, (int)n, dvifp);
special_buf[n] = '\0';
STRXCHAR(special_buf)
special(PASS2, special_buf, h, v);
break;
case FNT_DEF1 : case FNT_DEF1 + 1 :
case FNT_DEF1 + 2 : case FNT_DEF1 + 3 :
fseek(dvifp, 12L, 1);
n = uread1(dvifp);
n += uread1(dvifp);
fseek(dvifp, (long)n, 1);
break;
case POST :
if (nbuf)
set_string(buf, nbuf, startf, starth, startv);
return;
default :
bad_dvi_file();
}
}
}
static void bad_dvi_file()
{
message(FATAL_ERROR, "this dvi file is bad -- use dvitype");
}
/*
Local Variables:
tab-width: 4
c-indent-level: 4
c-continued-statement-offset: 4
c-brace-offset: -4
c-argdecl-indent: 0
c-label-offset: -4
End:
*/